package com.knowledge.plus.wait_notify;

import cn.hutool.core.date.DateUtil;

/**
 * wait 立即释放锁 与 notify / notifyAll 延迟通知
 *
 * @author TPF
 * @since 2024/3/11
 */
class MyService {

    private Object obj = new Object();

    public void waitFun() {
        try {
            synchronized (obj) {
                System.out.println("begin   wait: " + Thread.currentThread().getName() + " > " + DateUtil.date());
                obj.wait();
                System.out.println("end     wait: " + Thread.currentThread().getName() + " > " + DateUtil.date());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void notifyFun() {
        try {
            synchronized (obj) {
                System.out.println("begin notify: " + Thread.currentThread().getName() + " > " + DateUtil.date());
                obj.notify();
                System.out.println("end   notify: " + Thread.currentThread().getName() + " > " + DateUtil.date());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ThreadA extends Thread {
    private MyService myService;

    public ThreadA(String name, MyService myService) {
        super(name);
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.waitFun();
    }
}

class ThreadB extends Thread {
    private MyService myService;

    public ThreadB(String name, MyService myService) {
        super(name);
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.notifyFun();
    }
}

/**
 * a线程调用wait方法进行中断，立即释放锁；
 * main线程睡眠1000ms后，b线程启动获得对象锁开始通知，然后执行.notify语句；
 * 执行完了b线程同步方法，a线程收到通知，从中断处继续向下执行，最后得到结果。
 */
public class WaitNotifyDemo {

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        ThreadA a = new ThreadA("ThreadA", myService);
        a.start();

        Thread.sleep(5000);

        ThreadB b = new ThreadB("ThreadB", myService);
        b.start();
    }

}
